#include "scene.h"

#include "utils/commands.h"

Scene::Scene(int argc, char* argv[])
 : frameCounter(0)
{
	Cdcommands::Instance()->scene = this;
 	BeEventSystem::Instance()->setCommandsystem( Cdcommands::Instance() );

	settings = Settings::Instance();
	drawdebug = settings->getCVarPtr("drawdebug");
	headless = settings->getCVarPtr("headless");
	settings->registerLocalCVar("version", "0.02a", "version");
	
	// register COMMANDS
		Cdcommands::Instance()->registerCmd("quit", &Scene::quit);
// 		Cdcommands::Instance()->registerCmd("critter_pick", &Scene::pickBody);
// 		Cdcommands::Instance()->registerCmd("critter_unpick", &Scene::unpickBody);

		Cdcommands::Instance()->registerCmd("race_start", &Scene::race_start);
		
		Cdcommands::Instance()->registerCmd("gui_togglepanel", 	&Scene::canvas_swapchild);

		// FIXME 1 AXIS
		Cdcommands::Instance()->registerCmd("car_steering", &Scene::car_steering);
		Cdcommands::Instance()->registerCmd("car_throttle", &Scene::car_throttle);
		Cdcommands::Instance()->registerCmd("car_braking", &Scene::car_braking);

		Cdcommands::Instance()->registerCmd("car_steerleft", &Scene::steerleft);
		Cdcommands::Instance()->registerCmd("car_steerright", &Scene::steerright);

		
		Cdcommands::Instance()->registerCmd("car_accelforw", &Scene::accelforw);
		Cdcommands::Instance()->registerCmd("car_accelback", &Scene::accelback);
		Cdcommands::Instance()->registerCmd("car_handbrake", &Scene::handbrake);
		Cdcommands::Instance()->registerCmd("car_steerleft_rel", &Scene::steerleft_rel);
		Cdcommands::Instance()->registerCmd("car_steerright_rel", &Scene::steerright_rel);
		Cdcommands::Instance()->registerCmd("car_accelforw_rel", &Scene::accelforw_rel);
		Cdcommands::Instance()->registerCmd("car_accelback_rel", &Scene::accelback_rel);
		Cdcommands::Instance()->registerCmd("car_handbrake_rel", &Scene::handbrake_rel);

		Cdcommands::Instance()->registerCmd("carsetting_suspensionstiffness_inc", &Scene::carsetting_suspensionstiffness_inc);
		Cdcommands::Instance()->registerCmd("carsetting_suspensionstiffness_dec", &Scene::carsetting_suspensionstiffness_dec);
		Cdcommands::Instance()->registerCmd("carsetting_suspensiondamping_inc", &Scene::carsetting_suspensiondamping_inc);
		Cdcommands::Instance()->registerCmd("carsetting_suspensiondamping_dec", &Scene::carsetting_suspensiondamping_dec);
		Cdcommands::Instance()->registerCmd("carsetting_suspensioncompression_inc", &Scene::carsetting_suspensioncompression_inc);
		Cdcommands::Instance()->registerCmd("carsetting_suspensioncompression_dec", &Scene::carsetting_suspensioncompression_dec);
		Cdcommands::Instance()->registerCmd("carsetting_rollinfluence_inc", &Scene::carsetting_rollinfluence_inc);
		Cdcommands::Instance()->registerCmd("carsetting_rollinfluence_dec", &Scene::carsetting_rollinfluence_dec);
		Cdcommands::Instance()->registerCmd("carsetting_suspensionrestlength_inc", &Scene::carsetting_suspensionrestlength_inc);
		Cdcommands::Instance()->registerCmd("carsetting_suspensionrestlength_dec", &Scene::carsetting_suspensionrestlength_dec);
		Cdcommands::Instance()->registerCmd("carsetting_steeringincrement_inc", &Scene::carsetting_steeringincrement_inc);
		Cdcommands::Instance()->registerCmd("carsetting_steeringincrement_dec", &Scene::carsetting_steeringincrement_dec);
		Cdcommands::Instance()->registerCmd("carsetting_steeringclamp_inc", &Scene::carsetting_steeringclamp_inc);
		Cdcommands::Instance()->registerCmd("carsetting_steeringclamp_dec", &Scene::carsetting_steeringclamp_dec);
		Cdcommands::Instance()->registerCmd("carsetting_exponentialsteering_inc", &Scene::carsetting_exponentialsteering_inc);
		Cdcommands::Instance()->registerCmd("carsetting_exponentialsteering_dec", &Scene::carsetting_exponentialsteering_dec);
		
		Cdcommands::Instance()->registerCmd("joystick_toggle", &Scene::joystick_toggle);

		Cdcommands::Instance()->registerCmd("player_join", &Scene::player_join);
		Cdcommands::Instance()->registerCmd("player_unjoin", &Scene::player_unjoin);

		Cdcommands::Instance()->registerCmd("camera_moveup", &Scene::camera_moveup);
		Cdcommands::Instance()->registerCmd("camera_movedown", &Scene::camera_movedown);
		Cdcommands::Instance()->registerCmd("camera_moveforward", &Scene::camera_moveforward);
		Cdcommands::Instance()->registerCmd("camera_movebackward", &Scene::camera_movebackward);
		Cdcommands::Instance()->registerCmd("camera_moveleft", &Scene::camera_moveleft);
		Cdcommands::Instance()->registerCmd("camera_moveright", &Scene::camera_moveright);
		Cdcommands::Instance()->registerCmd("camera_lookup", &Scene::camera_lookup);
		Cdcommands::Instance()->registerCmd("camera_lookdown", &Scene::camera_lookdown);
		Cdcommands::Instance()->registerCmd("camera_lookleft", &Scene::camera_lookleft);
		Cdcommands::Instance()->registerCmd("camera_lookright", &Scene::camera_lookright);
		Cdcommands::Instance()->registerCmd("camera_rollleft", &Scene::camera_rollleft);
		Cdcommands::Instance()->registerCmd("camera_rollright", &Scene::camera_rollright);

		Cdcommands::Instance()->registerCmd("canvas_setx", &Scene::canvas_setx);
		Cdcommands::Instance()->registerCmd("canvas_sety", &Scene::canvas_sety);
		Cdcommands::Instance()->registerCmd("canvas_press", &Scene::canvas_press);
		Cdcommands::Instance()->registerCmd("canvas_release", &Scene::canvas_release);


	// load control settings file
	BeFile befileControls;
	if ( BeFilesystem::Instance()->load(befileControls, "settings.xml") )
	{
		m_settingsLoader.load( BeEventSystem::Instance(), &befileControls );
	}

	world.reset(new World);

	if ( *headless )
		Logbuffer::Instance()->headless = true;
}

void Scene::draw()
{
	frameCounter++;

	Timer::Instance()->mark();
	BeEventSystem::Instance()->processEvents( Timer::Instance()->elapsed );
	
	timeDelta = Timer::Instance()->elapsed / 1000.0f;
	m_cameraTranslateSpeed=40.0f*timeDelta; //0.5f**m_cameraSensitivity;
	m_cameraRotateSpeed=SIMD_PI*timeDelta; //0.0001f**m_cameraSensitivity;
	
	framelimiter.mark( Timer::Instance() );

	world->process( timeDelta ); // FIXME THIS IS NOT THE BEST SPOT TO BE

	if ( !*headless )
		world->draw();
}

// TODO EXAMPLE m_outputEventQueue.push(ScDigitalActionEvent(eActionSteerLeft, true));

	void Scene::canvas_setx( float value )
	{
		world->m_sc_client->m_canvas->moveMouseX(value);
	}

	void Scene::canvas_sety( float value )
	{
		world->m_sc_client->m_canvas->moveMouseY(value);
		world->m_sc_client->m_canvas->moveMouse();
	}

	void Scene::canvas_press()
	{
		world->m_sc_client->m_canvas->buttonPress( 1 );
	}
	void Scene::canvas_release()
	{
		world->m_sc_client->m_canvas->buttonRelease( 1 );
	}
	void Scene::canvas_swapchild(const string& child)
	{
		world->m_sc_client->m_canvas->swapChild( child );
	}

	void Scene::car_steering( float value )
	{
		if ( world->m_sc_client->me && world->m_sc_client->me->isJoined() )
		{
			world->m_sc_client->me->getCar()->gLinVehicleSteering = value;
			world->m_sc_client->me->getCar()->setExpSteering();
		}
	}

	void Scene::car_throttle( float value )
	{
		if ( world->m_sc_client->me && world->m_sc_client->me->isJoined() )
			world->m_sc_client->me->getCar()->m_throttle = value;
	}

	void Scene::car_braking( float value )
	{
		if ( world->m_sc_client->me && world->m_sc_client->me->isJoined() )
			world->m_sc_client->me->getCar()->m_braking = value;
	}

	void Scene::steerleft()
	{
		if ( world->m_sc_client->me && world->m_sc_client->me->isJoined() )
			world->m_sc_client->me->getCar()->m_left = true;
	}
	void Scene::steerright()
	{
		if ( world->m_sc_client->me && world->m_sc_client->me->isJoined() )
			world->m_sc_client->me->getCar()->m_right = true;
	}
	void Scene::steerleft_rel()
	{
		if ( world->m_sc_client->me && world->m_sc_client->me->isJoined() )
			world->m_sc_client->me->getCar()->m_left = false;
	}
	void Scene::steerright_rel()
	{
		if ( world->m_sc_client->me && world->m_sc_client->me->isJoined() )
			world->m_sc_client->me->getCar()->m_right = false;
	}

	void Scene::accelforw()
	{
		if ( world->m_sc_client->me && world->m_sc_client->me->isJoined() )
			world->m_sc_client->me->getCar()->m_throttle = 1.0f;
	}
	void Scene::accelforw_rel()
	{
		if ( world->m_sc_client->me && world->m_sc_client->me->isJoined() )
			world->m_sc_client->me->getCar()->m_throttle = 0.0f;
	}

	void Scene::accelback()
	{
		if ( world->m_sc_client->me && world->m_sc_client->me->isJoined() )
			world->m_sc_client->me->getCar()->m_throttle = -1.0f;
	}
	void Scene::accelback_rel()
	{
		if ( world->m_sc_client->me && world->m_sc_client->me->isJoined() )
			world->m_sc_client->me->getCar()->m_throttle = 0.0f;
	}

	void Scene::handbrake()
	{
		if ( world->m_sc_client->me && world->m_sc_client->me->isJoined() )
			world->m_sc_client->me->getCar()->m_braking = 1.0f;
	}
	void Scene::handbrake_rel()
	{
		if ( world->m_sc_client->me && world->m_sc_client->me->isJoined() )
			world->m_sc_client->me->getCar()->m_braking = 0.0f;
	}

	// race control
	void Scene::race_start() { world->m_sc_client->pushOutgoingmessage("sr 1;"); }
	void Scene::player_join()
	{
		world->m_sc_client->pushOutgoingmessage("jo 1;");
		
// 		if ( *client )
// 		{
			stringstream buf;
// 			buf << "cs1 " << settings->getCVar("carsetting_suspensionstiffness") << ";";
// 			buf << "cs2 " << settings->getCVar("carsetting_suspensiondamping") << ";";
// 			buf << "cs3 " << settings->getCVar("carsetting_suspensioncompression") << ";";
// 			buf << "cs4 " << settings->getCVar("carsetting_rollinfluence") << ";";
			buf << "cs5 " << settings->getCVar("carsetting_steeringincrement") << ";";
			buf << "cs6 " << settings->getCVar("carsetting_steeringclamp") << ";";
			buf << "cs7 " << settings->getCVar("carsetting_exponentialsteering") << ";";
// 			buf << "cs8 " << settings->getCVar("carsetting_suspensionrestlength") << ";";
			world->m_sc_client->pushOutgoingmessage(buf.str());
// 		}
		// send all settings over
	}
	void Scene::player_unjoin() { world->m_sc_client->pushOutgoingmessage("uj 1;"); }
	
	// car settings
	void Scene::carsetting_suspensionstiffness_inc()
	{
		settings->increaseCVar("carsetting_suspensionstiffness", 1); stringstream buf; buf << "cs1 " << settings->getCVar("carsetting_suspensionstiffness") << ";";
		world->m_sc_client->pushOutgoingmessage(buf.str());
	}
	void Scene::carsetting_suspensionstiffness_dec()
	{
		settings->decreaseCVar("carsetting_suspensionstiffness", 1); stringstream buf; buf << "cs1 " << settings->getCVar("carsetting_suspensionstiffness") << ";";
		world->m_sc_client->pushOutgoingmessage(buf.str());
	}
	void Scene::carsetting_suspensiondamping_inc()
	{
		settings->increaseCVar("carsetting_suspensiondamping", 1); stringstream buf; buf << "cs2 " << settings->getCVar("carsetting_suspensiondamping") << ";";
		world->m_sc_client->pushOutgoingmessage(buf.str());
	}
	void Scene::carsetting_suspensiondamping_dec()
	{
		settings->decreaseCVar("carsetting_suspensiondamping", 1); stringstream buf; buf << "cs2 " << settings->getCVar("carsetting_suspensiondamping") << ";";
		world->m_sc_client->pushOutgoingmessage(buf.str());
	}
	void Scene::carsetting_suspensioncompression_inc()
	{
		settings->increaseCVar("carsetting_suspensioncompression", 1); stringstream buf; buf << "cs3 " << settings->getCVar("carsetting_suspensioncompression") << ";";
		world->m_sc_client->pushOutgoingmessage(buf.str());
	}
	void Scene::carsetting_suspensioncompression_dec()
	{
		settings->decreaseCVar("carsetting_suspensioncompression", 1); stringstream buf; buf << "cs3 " << settings->getCVar("carsetting_suspensioncompression") << ";";
		world->m_sc_client->pushOutgoingmessage(buf.str());
	}
	void Scene::carsetting_rollinfluence_inc()
	{
		settings->increaseCVar("carsetting_rollinfluence", 1); stringstream buf; buf << "cs4 " << settings->getCVar("carsetting_rollinfluence") << ";";
		world->m_sc_client->pushOutgoingmessage(buf.str());
	}
	void Scene::carsetting_rollinfluence_dec()
	{
		settings->decreaseCVar("carsetting_rollinfluence", 1); stringstream buf; buf << "cs4 " << settings->getCVar("carsetting_rollinfluence") << ";";
		world->m_sc_client->pushOutgoingmessage(buf.str());
	}
	void Scene::carsetting_suspensionrestlength_inc()
	{
		settings->increaseCVar("carsetting_suspensionrestlength", 1); stringstream buf; buf << "cs8 " << settings->getCVar("carsetting_suspensionrestlength") << ";";
		world->m_sc_client->pushOutgoingmessage(buf.str());
	}
	void Scene::carsetting_suspensionrestlength_dec()
	{
		settings->decreaseCVar("carsetting_suspensionrestlength", 1); stringstream buf; buf << "cs8 " << settings->getCVar("carsetting_suspensionrestlength") << ";";
		world->m_sc_client->pushOutgoingmessage(buf.str());
	}
	
	void Scene::carsetting_steeringincrement_inc()
	{
		settings->increaseCVar("carsetting_steeringincrement", 1); stringstream buf; buf << "cs5 " << settings->getCVar("carsetting_steeringincrement") << ";";
		world->m_sc_client->pushOutgoingmessage(buf.str());
	}
	void Scene::carsetting_steeringincrement_dec()
	{
		settings->decreaseCVar("carsetting_steeringincrement", 1); stringstream buf; buf << "cs5 " << settings->getCVar("carsetting_steeringincrement") << ";";
		world->m_sc_client->pushOutgoingmessage(buf.str());
	}
	void Scene::carsetting_steeringclamp_inc()
	{
		settings->increaseCVar("carsetting_steeringclamp", 1); stringstream buf; buf << "cs6 " << settings->getCVar("carsetting_steeringclamp") << ";";
		world->m_sc_client->pushOutgoingmessage(buf.str());
	}
	void Scene::carsetting_steeringclamp_dec()
	{
		settings->decreaseCVar("carsetting_steeringclamp", 1); stringstream buf; buf << "cs6 " << settings->getCVar("carsetting_steeringclamp") << ";";
		world->m_sc_client->pushOutgoingmessage(buf.str());
	}
	void Scene::carsetting_exponentialsteering_inc()
	{
		settings->increaseCVar("carsetting_exponentialsteering", 1); stringstream buf; buf << "cs7 " << settings->getCVar("carsetting_exponentialsteering") << ";";
		world->m_sc_client->pushOutgoingmessage(buf.str());
	}
	void Scene::carsetting_exponentialsteering_dec()
	{
		settings->decreaseCVar("carsetting_exponentialsteering", 1); stringstream buf; buf << "cs7 " << settings->getCVar("carsetting_exponentialsteering") << ";";
		world->m_sc_client->pushOutgoingmessage(buf.str());
	}

	void Scene::joystick_toggle()
	{
// 		cerr << "hi" << endl;
		settings->increaseCVar("joystick", 1);
// 		stringstream buf;
// 		buf << "js " << settings->getCVar("joystick") << ";";
// // 		cout << buf.str() << endl;
// 		world->m_sc_client->pushOutgoingmessage(buf.str());
	}

	// camera
	void Scene::camera_moveup() 		
	{ 
		BeSceneNode* const sceneNode=world->m_sc_client->m_camera.getSceneNode();
		if(sceneNode)
		{
			sceneNode->translateLocal(btVector3(0,m_cameraTranslateSpeed,0));
		}
// 		movePickedBodyFrom(); 
	}

	void Scene::camera_movedown() 		
	{
		BeSceneNode* const sceneNode=world->m_sc_client->m_camera.getSceneNode();
		if(sceneNode)
		{
			sceneNode->translateLocal(btVector3(0,-m_cameraTranslateSpeed,0));
		}
// 		movePickedBodyFrom(); 
	}

	void Scene::camera_moveforward() 	
	{ 
		BeSceneNode* const sceneNode=world->m_sc_client->m_camera.getSceneNode();
		if(sceneNode)
		{
			sceneNode->translateLocal(btVector3(0,0,-m_cameraTranslateSpeed));
		}
// 		movePickedBodyFrom(); 
	}

	void Scene::camera_movebackward() 	
	{ 
		BeSceneNode* const sceneNode=world->m_sc_client->m_camera.getSceneNode();
		if(sceneNode)
		{
			sceneNode->translateLocal(btVector3(0,0,m_cameraTranslateSpeed));
		}
// 		movePickedBodyFrom(); 
	}

	void Scene::camera_moveleft() 		
	{ 
		BeSceneNode* const sceneNode=world->m_sc_client->m_camera.getSceneNode();
		if(sceneNode)
		{
			sceneNode->translateLocal(btVector3(-m_cameraTranslateSpeed,0,0));
		}
// 		movePickedBodyFrom(); 
	}

	void Scene::camera_moveright() 		
	{ 
		BeSceneNode* const sceneNode=world->m_sc_client->m_camera.getSceneNode();
		if(sceneNode)
		{
			sceneNode->translateLocal(btVector3(m_cameraTranslateSpeed,0,0));
		}
// 		movePickedBodyFrom(); 
	}

	void Scene::camera_lookup() 		
	{ 
		BeSceneNode* const sceneNode=world->m_sc_client->m_camera.getSceneNode();
		if(sceneNode)
		{
			sceneNode->pitch(m_cameraRotateSpeed);
		}
// 		calcMouseDirection(); 
// 		movePickedBodyTo(); 
	}
	void Scene::camera_lookdown() 		
	{ 
		BeSceneNode* const sceneNode=world->m_sc_client->m_camera.getSceneNode();
		if(sceneNode)
		{
			sceneNode->pitch(-m_cameraRotateSpeed);
		}
// 		calcMouseDirection(); 
// 		movePickedBodyTo(); 
	}
	void Scene::camera_lookleft() 		
	{ 
		BeSceneNode* const sceneNode=world->m_sc_client->m_camera.getSceneNode();
		if(sceneNode)
		{
			sceneNode->yaw(m_cameraRotateSpeed); 
		}
// 		calcMouseDirection(); 
// 		movePickedBodyTo(); 
	}
	void Scene::camera_lookright() 		
	{ 
		BeSceneNode* const sceneNode=world->m_sc_client->m_camera.getSceneNode();
		if(sceneNode)
		{
			sceneNode->yaw(-m_cameraRotateSpeed);
		}
// 		calcMouseDirection(); 
// 		movePickedBodyTo(); 
	}
	void Scene::camera_rollleft() 		
	{ 
		BeSceneNode* const sceneNode=world->m_sc_client->m_camera.getSceneNode();
		if(sceneNode)
		{
			sceneNode->roll(m_cameraRotateSpeed); 		
		}
// 		calcMouseDirection(); 
// 		movePickedBodyTo(); 
	}
	void Scene::camera_rollright() 		
	{ 
		BeSceneNode* const sceneNode=world->m_sc_client->m_camera.getSceneNode();
		if(sceneNode)
		{
			sceneNode->roll(-m_cameraRotateSpeed); 
		}	
// 		calcMouseDirection(); 
// 		movePickedBodyTo(); 
	}

// 	void Scene::camera_lookhorizontal() 	{ world->camera.lookRight((float)world->relx/3000); 	calcMouseDirection(); movePickedBodyTo(); }
// 	void Scene::camera_lookvertical() 	{ world->camera.lookDown((float)world->rely/3000); 	calcMouseDirection(); movePickedBodyTo(); }
// 	void Scene::camera_movehorizontal() 	{ world->camera.moveRight((float)world->relx/300); 	movePickedBodyFrom(); }
// 	void Scene::camera_movevertical() 	{ world->camera.moveDown((float)world->rely/300); 	movePickedBodyFrom(); }
// void Scene::handleMouseMotionAbs( int x, int y )
// {
// 	absmousex = x;
// 	absmousey = y;
// 	
// 	// gui mouse dynamics
// 	canvas.moveMouse(x, y);
// 
// 	// world mouse dynamics
// 	calcMouseDirection();
// 	movePickedBodyTo();
// }

// COMMANDS

	// mouse raycasting
// 		void Scene::calcMouseDirection()
// 		{
// 			world->mouseRayTo = world->m_camera.getScreenDirection( absmousex, absmousey );
// 		}

// /*		void Scene::castMouseRay()
// 		{
// 			mouseRay = raycast->cast( world->camera.position.getOrigin(), mouseRayTo );
// 
// 			mouseRayHit = false;
// 			if ( mouseRay.hit )
// 			{
// 				if ( !( mouseRay.hitBody->isStaticObject() || mouseRay.hitBody->isKinematicObject() ) )
// 				{
// 					mouseRayHitEntity = static_cast<Entity*>(mouseRay.hitBody->getUserPointer());
// 					mouseRayHit = true;
// 				}
// 			}
// 		}*/

	// mouse picking
// 		void Scene::movePickedBodyTo()
// 		{
// 			if ( mousepicker->active )
// 			{
// 				mousepicker->moveTo( world->camera.position.getOrigin(), world->mouseRayTo );
// 			}
// 		}

// 		void Scene::movePickedBodyFrom()
// 		{
// 			if ( mousepicker->active )
// 			{
// 				mousepicker->moveFrom( world->camera.position.getOrigin() );
// 			}
// 		}

// 		void Scene::unpickBody()
// 		{
// 			mousepicker->detach();
// 		}

// 		void Scene::pickBody()
// 		{
// 			if ( world->mouseRayHit )
// 			{
// 				btRigidBody* b = static_cast<btRigidBody*>(world->mouseRay.hitBody);
// 
// 				mousepicker->attach( b, world->mouseRay.hitPosition, world->camera.position.getOrigin(), world->mouseRayTo );
// 
// 				mousepicker->pickedBool = &world->mouseRayHitEntity->isPicked;
// 				*mousepicker->pickedBool = true;
// 			}
// 		}


Scene::~Scene()
{
	cerr << "exiting scene" << endl;
	BeModelSystem::Instance()->emptyStore();
// 	cerr << "scene deconstruct" << endl;
}
